-------------Math Leap Frog------------
A 4am crack                  2016-09-12
---------------------------------------

Name: Math Leap Frog
Version: 3.1.6
Genre: educational
Year: 1987
Publisher: Gamco Industries, Inc.
Platform: Apple ][+ or later
Media: double-sided 5.25-inch floppy
OS: ProDOS 1.1.1
Previous cracks: none
Similar cracks:
  #826 Math Football
  #795 Treasure Dive
  #794 Grammar Baseball
  #686 The Word Problem Game Show
  #685 Eureka: Following Directions

                   ~

               Chapter 0
 In Which Various Automated Tools Fail
          In Interesting Ways


COPYA
  fails on last pass (both sides)

Locksmith Fast Disk Backup
  unable to read track $22 --
  copy boots ProDOS, prints "BEAGLE
  COMPILER 3.2", then prints "NOT AN
  EXECUTABLE DISK." and hangs

EDD 4 bit copy (no sync, no count)
  works

Copy ][+ nibble editor
  track $22 is entirely unformatted

Disk Fixer
  T00 -> looks like standard ProDOS
  no way to read T22

Why didn't COPYA work?
  intentionally unformatted track

Why didn't Locksmith FDB work?
  Probably a runtime protection check
  to ensure track $22 is unreadable

EDD works. What does that tell us?
  The protection check is probably very
  simple, just checking that track $22
  is unreadable.

Next steps:

  1. Search for protection check
  2. Disable it
  3. Declare victory(*)

(*) Go to the gym

                   ~

               Chapter 1
          How Do I Read Thee?
         Let Me Count The Ways


On the theory that some code on disk is
trying to access track $22, and thus
noticing if it's unexpectedly readable,
let's enumerate some of the ways that
could happen:

- Reading a file that is mapped to the
  unreadable track $22. Copy II+ disk
  map shows there are no files mapped
  to track $22, so let's rule that out.

- Manually seeking to the track and
  looking for a nibble sequence. Given
  that this disk is ProDOS-based, there
  is no explicit support for "seeking
  to a particular track" unless you're
  calling ProDOS internals. (But that's
  always possible, of course!) Without
  calling into ProDOS, this technique
  would require low-level disk access
  (turning on the drive and hitting the
  right stepper motors and whatnot). A
  sector search with Disk Fixer didn't
  find any suspicious instances of

  "BD 89 C0" (LDA $C089,X)   ; drive on
  "AD E9 C0" (LDA $C0E9)     ; drive on
  "BD 80 C0" (LDA $C080,X)   ; stepper

  or any similar variations that would
  point to low-level disk access.

- Issuing a ProDOS MLI "raw block read"
  and checking the return code. This is
  a popular technique under ProDOS,
  partly because it can be adapted to
  work on 3.5-inch and 5.25-inch disks.
  Combined with the knowledge that EDD
  bit copy produced a working copy, I
  suspect this is what I'm looking for.

Unfortunately, a sector search for
"20 00 BF 80" (JSR $BF00 / [80]) -- the
standard opcode sequence for calling
the ProDOS MLI with command $80 (block
read) -- turned up nothing at all.
Which means, perhaps, that this entire
chapter was just mental gymnastics.

Or is it? Dun dun DUN...

                   ~

               Chapter 2
 Lies, Damned Lies, And Error Messages


After striking out looking for the
protection check, let's change tactics
and look for the error string instead.
My non-working copy prints the message
"NOT AN EXECUTABLE DISK" after booting
ProDOS, launching the Beagle Compiler,
and executing the startup program -- a
delightfully bald-faced lie only a copy
protection developer could love.

Searching for the string "EXECUTABLE"
finds nothing, but wait! Disk Fixer
also supports finding strings with the
low bit clear. Pressing "T" twice to
change from "NORMAL" to "INVERSE" to
"FLASH" mode, then "F"ind "A"SCII and
search for "EXECUTABLE" again. Lo and
behold, it finds a match on track $0D.

                 --v--

-------------- DISK EDIT ---------------
TRACK $0D/SECTOR $01/VOLUME $FE/BYTE $A9
----------------------------------------
$80: 1F 7C 96 30 BF 6E 96 F0    .|.0?n.p
$88: 1F 4A A4 7C 96 EF 1F 94    .J$|.o..
$90: 27 09 97 00 0A 98 00 0E    '.......
$98: 28 66 94 0A 64 94 09 1C    (f..d...
$A0: 9A 17 4E 4F 54 20 41 4E    ..NOT AN
           ^^^^^^^^^^^^^^^^^
            lies! all lies!

$A8: 20>45<58 45 43 55 54 41     EXECUTA
     ^^^^^^^^^^^^^^^^^^^^^^^

$B0: 42 4C 45 20 44 49 53 4B    BLE DISK
     ^^^^^^^^^^^^^^^^^^^^^^^

$B8: 2E 24 0A BA 00 12 02 33    .$.:...3
$C0: 32 01 30 03 31 39 31 03    2.0.191.
$C8: 31 32 38 03 32 35 30 02    128.250.
$D0: 33 31 03 31 34 31 03 32    31.141.2
$D8: 33 39 02 33 31 02 39 36    39.31.96
$E0: 01 33 02 39 36 01 30 01    .3.96.0.
$E8: 32 02 31 37 01 31 FF 12    2.17.1..
$F0: 00 00 00 00 00 00 00 00    ........
$F8: 00 00 00 00 00 00 00 00    ........
----------------------------------------
BUFFER 0/SLOT 6/DRIVE 1/MASK OFF/FLASH

----------------------------------------
COMMAND : _

                 --^--

Starting at byte $BF, I spy with my
little eye a sequence of numbers
written out as strings:

32 0 191 128 250 31 141 239 31 96

...and so on. Each is preceded by a hex
byte #$01, #$02, or #$03, which appears
to be the length in character of the
number as a string. "32" is always
preceded by #$02 because it's a 2-digit
number -- er, string -- while "191" is
preceded by #$03 because it's a 3-digit
number string.

So what is this sequence? They seem to
be base 10 numbers between 0 and 255.
Converted to base 16, they turn out to
be quite interesting indeed:

 32 -> $20
  0 -> $00
191 -> $BF
128 -> $80
250 -> $FA
 31 -> $1F
141 -> $8D
239 -> $EF
 31 -> $1F
 96 -> $60
  3 -> $03
 96 -> $60
  0 -> $00
  2 -> $02
 17 -> $11
  1 -> $01

"20 00 BF" looks suspiciously like 6502
assembly code. (It's a call to the
ProDOS MLI subroutine at $BF00.) The
rest of it fits my theory that this
ends up as executable code. I like data
that fits my theory. That's so much
easier than changing my theory to fit
the data. Boring!

Dropping into the monitor, I can see it
in its native form:

*1FF0:20 00 BF 80 FA 1F 8D EF 1F 60 03
 60 00 02 11 01

*1FF0L

1FF0-   20 00 BF    JSR   $BF00
1FF3-  [80]         ; MLI block read
1FF4-  [FA 1F]      ; MLI param address
1FF6-   8D EF 1F    STA   $1FEF
1FF9-   60          RTS
1FFA-  [03]         ; MLI param count
1FFB-  [60]         ; unit number
1FFC-  [00 02]      ; buffer address
1FFE-  [11 01]      ; block number

Note: block $0111 is on the unreadable
track $22!

I think I know what I'm looking at
here. This (compiled) BASIC program is
taking a sequence of numbers and
POKE-ing them into memory, then calling
that assembly language routine to
accomplish what would otherwise
impossible from pure BASIC -- calling
the ProDOS MLI with a raw block read,
and storing the result.

According to "Beneath Apple ProDOS"
(p. 6-19), the return codes from a raw
block read (MLI code $80) are

  $00 - no errors
  $04 - incorrect parameter count
  $27 - I/O error or bad block number
  $28 - drive not found
  $56 - buffer already in use

Since the original disk's track $22 is
unformatted and thus unreadable, I'm
guessing the "correct" answer is $27
("I/O error"). I can change this
routine so it simply puts the expected
value in memory address $1FEF.

*1FF0:2C
*1FF3:EA A9 27
*1FF0L

1FF0-   2C 00 BF    BIT   $BF00
1FF3-   EA          NOP
1FF4-   A9 27       LDA   #$27
1FF6-   8D EF 1F    STA   $1FEF
1FF9-   60          RTS

Converting this hacked routine back to
decimal would yield the sequence

44 0 191 234 169 39 [...]

...which happens to be exactly as long
as the original number-string sequence:

32 0 191 128 250 31 [...]

T0D,S01,$BF: 33 32    -> 34 34
T0D,S01,$C8: 31 32 38 -> 32 33 34
T0D,S01,$CC: 32 35 30 -> 31 36 39
T0D,S01,$D1: 31       -> 39

]PR#6
...works, and it is glorious...

Side B is unprotected.

Quod erat liberandum.

---------------------------------------
A 4am crack                     No. 839
------------------EOF------------------
